package com.ruoyi.wms.common;

import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Threads;
import com.ruoyi.common.utils.spring.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * Desc     OrderNo生成器
 * Project  ry-wms
 * Package  com.ruoyi.wms.common
 * Author   zhangyunlong@prevailcloud.com
 * Date     2023/2/2
 */
public abstract class OrderNoGenerator
{

    private static final Logger log = LoggerFactory.getLogger(OrderNoGenerator.class);

    private static final String YYYYMMDDHHMMSSSSS = "yyyyMMddHHmmss-SSSSS";
    /**
     * 入库单号前缀
     */
    private static final String RECEIPT_PREFIX    = "R";
    /**
     * 出库单号前缀
     */
    private static final String SHIPMENT_PREFIX   = "C";

    private static final String ORDER_NO_GENERATOR_REDIS_KEY = "GENERATOR:ORDER_NO";

    private static String getBaseOrderNo()
    {
        String baseOrderNo = "";
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);

        // 使用缓存来尽量避免生成重复的订单号
        Integer index = 0;
        Integer max = 100;
        boolean hasKey = true;
        while (hasKey && index <= max)
        {
//            log.debug("index : {}", index);
            //  100 次之后直接失败
            if (index == max) return "";
            index++;
            synchronized (index)
            {
                // 生成redis主键
                baseOrderNo = DateUtils.dateTimeNow(YYYYMMDDHHMMSSSSS);

                String redisKey = redisKey(baseOrderNo);
//                log.debug(" baseOrderNo:{}, redisKey:{}, hasRedisKey:{}", baseOrderNo, redisKey, redisCache.hasKey(redisKey));
                // 缓存中已经存在，等待一毫秒继续生成
                if (redisCache.hasKey(redisKey))
                {
                    Threads.sleep(1);
                    baseOrderNo = DateUtils.dateTimeNow(YYYYMMDDHHMMSSSSS);
                }
                // 缓存中不存在，放入缓存，跳出循环
                else
                {
                    hasKey = false;
                    redisCache.setCacheObject(redisKey, null, 10, TimeUnit.SECONDS);
                }
            }
        }
        return baseOrderNo;
    }

    private static String redisKey(String val)
    {
        return ORDER_NO_GENERATOR_REDIS_KEY + ":" + val;
    }

    public static String nextReceiptOrderNo()
    {
        String baseOrderNo = getBaseOrderNo();
        if (StringUtils.isBlank(baseOrderNo)) return "";
        return RECEIPT_PREFIX + "-" + baseOrderNo;
    }

    public static String nextShipmentOrderNo()
    {
        String baseOrderNo = getBaseOrderNo();
        if (StringUtils.isBlank(baseOrderNo)) return "";
        return SHIPMENT_PREFIX + "-" + baseOrderNo;
    }

}
